package xyz.cerberu.cet.log.aspect;


import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import xyz.cerberu.cet.global.domain.Global;
import xyz.cerberu.cet.global.domain.Result;
import xyz.cerberu.cet.global.utils.AopUtils;
import xyz.cerberu.cet.global.utils.RequestUtils;
import xyz.cerberu.cet.log.annotation.Logger;
import xyz.cerberu.cet.log.doamin.Log;
import xyz.cerberu.cet.log.service.LogServiceImpl;
import xyz.cerberu.cet.user.domain.User;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;

/**
 * @author β世界
 * Created on 18:41
 * @Description
 */
@Component
@Aspect
public class LogAspect {
    private final LogServiceImpl logServiceImpl;
    private final Global global;

    @Autowired
    public LogAspect(LogServiceImpl logServiceImpl, Global global) {
        this.logServiceImpl = logServiceImpl;
        this.global = global;
    }

    @Around("@annotation(xyz.cerberu.cet.log.annotation.Logger)")
    public Object aroundAdvice (ProceedingJoinPoint point) throws Throwable {
        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Logger logger = methodSignature.getMethod().getAnnotation(Logger.class);
        // 获取logType属性
        String logType = logger.logType();

        // 创建日志对象
        Log log = new Log();
        // 设置默认的事务等级
        log.setLevel(logger.logLevel());
        Object result = null;
        try{
            // 根据不同的方式来执行不同的日志处理对象
            switch (logType){
                // 爬虫记录
                case "spider":
                    result = spiderLog(point,log);
                    break;
                case "register":
                    // 注册账户的日志处理
                    result = registerLog(point,log);
                    break;
                case "login":
                    // 登陆的日志处理
                    result = loginLog(point,log);
                    break;
                default:
                    log = new Log();
                    log.setMessage(new StringBuilder().append(
                            log.getMessage()+"异常日志处理，调用方法："+
                                    point.getSignature().getDeclaringTypeName() +
                                    "."+ point.getSignature().getName()).toString());
                    log.setLevel(2);
                    break;
            }

            log.setLevel(1);
        }catch (Exception e){
            // 方法抛出异常，进行执行错误的登记处理
            log.setLevel(2);
            log.setMessage(log.getMessage() + " 执行异常：" + e.toString());
            e.printStackTrace();
        }finally {
            log.setDate(new Timestamp(System.currentTimeMillis()));
            // 检测是否符合日志记录等级
            if(global.getLogLevel() >= log.getLevel()){
                // 将这个日志对象写入方法中
                logServiceImpl.addLog(log);
            }
        }
        return result;
    }

    /**
     * @author β世界 on 16:50 2020/8/17
     * 对于爬虫的日志登记
     * @param point: 切点内容
     * @return com.Cet.log.doamin.Log
     **/
    private Object spiderLog(ProceedingJoinPoint point,Log log){
        return null;
    }

    /**
     * @author β世界 on 22:38 2020/9/7
     * 注册账户的日志系统，记录用户的注册行为
     * 当用户发送注册的时候，记录注册者的邮箱，还有IP地址。以及验证码的验证正确
     * @param point: 切点内容
     * @return com.Cet.log.domain.Log
     **/
    private Object registerLog(ProceedingJoinPoint point,Log log) throws Throwable {
        log.setType("register");
        StringBuilder stringBuilder = new StringBuilder();
        HttpServletRequest requests = (HttpServletRequest) AopUtils.getParamenter(HttpServletRequest.class,"request",point);
        User user = (User) AopUtils.getParamenter(User.class,"user",point);
        log.setMessage(stringBuilder.append(
                "用户注册 Email: "+user.getEmail()+
                " 用户名为: "+user.getUsername()+
                " IP地址: "+ RequestUtils.getIpAddress(requests)).toString());
        Result result = (Result)point.proceed();
        log.setMessage(stringBuilder.append(" 注册结果: "+result.getMessage()).toString());
        return requests;
    }

    /**
     * @author β世界 on 22:40 2020/9/7
     * 登陆账户的日志处理
     * 特殊情况:用户没有成功登陆(乱输入，输入错误，系统错误)
     * 登陆成功之后就会记录操作者
     * @param point: 切点内容
     * @return com.Cet.log.doamin.Log
     **/
    private Object loginLog(ProceedingJoinPoint point,Log log) throws Throwable {
        log.setType("login");
        // 获取登陆的用户，登陆的IP,登陆IP地址
        StringBuilder stringBuilder = new StringBuilder();
        HttpServletRequest requset = (HttpServletRequest) AopUtils.getParamenter(HttpServletRequest.class,"request",point);
        User user = (User) AopUtils.getParamenter(User.class,"user",point);
        log.setMessage(stringBuilder.append("用户登陆 Email: "+user.getEmail()+
                " IP地址: "+ RequestUtils.getIpAddress(requset)).toString());
        // 执行任务,登陆失败后将会触发异常，并且抛出向上处理，不会处理到下面的内容
        Result result = (Result)point.proceed();
        // 获取成功登陆的用户
        user = (User) SecurityUtils.getSubject().getPrincipal();
        if(user != null){
            log.setOperateor(user.getUid());
            log.setMessage(stringBuilder.append(" 权限: "+ user.getRole().getRole()).toString());
        }else {
            log.setMessage(stringBuilder.append(" 结果: "+ result.getMessage()).toString());
        }
        // 设置为正常日志
        return result;
    }
}
